﻿#include"unrealircd.h"

WebUser *current_User;
char *header_field;
char *header_value;
int chunk_length;
int http_head_completed;
llhttp_t *parser;
llhttp_settings_t *http_settings;
int on_chunk_header(llhttp_t* llhttp) {	
	chunk_length=llhttp->content_length;
	return 0;
}


void llhttpSetting_init(){
	parser=safe_alloc(sizeof(llhttp_t));
	http_settings=safe_alloc(sizeof(llhttp_settings_t));
	llhttp_settings_init(http_settings);
	http_settings->on_header_field = on_header_field;
	http_settings->on_header_value = on_header_value;
	http_settings->on_url = on_url;
	http_settings->on_headers_complete=handle_on_headers_complete;
	http_settings->on_body=handle_on_Onbody;
	http_settings->on_chunk_header=on_chunk_header;


	llhttp_init(parser, HTTP_REQUEST, http_settings);
}

int on_header_field(llhttp_t* llhttp, const char *at, size_t length) {
	safe_strldup(header_field,at,length+1);
	// ircd_log(LOG_ERROR,"on_header_field:%s",header_field);
	return 0;
}
int on_header_value(llhttp_t* llhttp, const char *at, size_t length) {
	safe_strldup(header_value,at,length+1);
	// ircd_log(LOG_ERROR,"on_header_value:%s",header_value);
	if(!header_field||is_empty_string(header_value,length)){
		return -1;
	}
	if(!strcasecmp(header_field,"Content-Length")){
		if(!is_digist_string(header_value,length)){
			return -1;
		}
		current_User->requestData->trans_mode=TRANSMODE_CONTENT_LENGTH;
		current_User->requestData->content_length=atoi(header_value);
	}
	else if(current_User->requestData->trans_mode==TRANSMODE_NO&&!strcasecmp(header_field,"Transfer-Encoding")){
		current_User->requestData->trans_mode=TRANSMODE_TRANSFER_ENCODING;
	}
	requestData_add_header(current_User->requestData,header_field,header_value);
	safe_free(header_field);
	safe_free(header_value);
	return 0;
}
int on_url(llhttp_t* llhttp, const char *at, size_t length) {
	char *url=urldecode(at,length);
	char *params=strchr(url,'?');
	if(params){
		*params='\0';
		params++;
		while(params&&(*params)){
			char *nextparams=strchr(params,'&');
			int len=0;
			if(nextparams){
				*nextparams='\0';
			}
			len=strlen(params);
			char *eqchar=strchr(params,'=');
			if(!eqchar){
				if(nextparams){
					params=nextparams+1;
				}
				else{
					params=NULL;
				}
				continue;
			}
			*eqchar='\0';
			char *param_name=NULL;
			char *param_value=NULL;
			safe_strdup(param_name,params);
			eqchar++;
			safe_strdup(param_value,eqchar);
			requestData_add_paramList(current_User->requestData,param_name,param_value);
			if(nextparams){
				params=nextparams+1;
			}
			else{
				params=NULL;
			}
		}

	}
	safe_strdup(current_User->requestData->requestUrl,url);
	safe_free(url);
	return 0;
}
int httpRequestReceivedDone(){
	if(!http_head_completed){
		return 0;
	}
	if(current_User->requestData->trans_mode==TRANSMODE_TRANSFER_ENCODING){
		if(chunk_length==0){
			return 1;
		}
		else{
			return 0;
		}
	}
	else if(current_User->requestData->trans_mode==TRANSMODE_CONTENT_LENGTH){
		if(current_User->requestData->requestBodyLength==current_User->requestData->content_length){
			return 1;
		}
		else{
			return 0;
		}
	}
	else{
		safe_free(current_User->requestData->requestBody);
		current_User->requestData->requestBodyLength=0;
		return 1;

	}
}
int handle_on_Onbody(llhttp_t* llhttp, const char *at, size_t length) {
	int newbodyLength=current_User->requestData->requestBodyLength+length;
	current_User->requestData->requestBody=realloc(current_User->requestData->requestBody,newbodyLength+1);
	for(int i=0;i<length;i++){
		current_User->requestData->requestBody[current_User->requestData->requestBodyLength+i]=at[i];
	}
	current_User->requestData->requestBody[newbodyLength]='\0';
	current_User->requestData->requestBodyLength=newbodyLength;
	return 0;
}
int handle_on_headers_complete(llhttp_t* llhttp) {
	http_head_completed=1;
	int method=0;
	switch(llhttp->method){
		case HTTP_GET:
			method=REQUEST_GET;
			break;
		case HTTP_DELETE:
			method=REQUEST_DELETE;
			break;
		case HTTP_POST:
			method=REQUEST_POST;
			break;
		case HTTP_PUT:
			method=REQUEST_PUT;
			break;
		case HTTP_HEAD:
			method=REQUEST_HEAD;
			break;
	}
	current_User->requestData->requestMethod=method;
	return 0;
}
/**
 * 解析http协议并且判断http请求传输是否完成，如果未完成保存已经传输的数据。
 * 返回值：
 * 0：数据正确，并且传输完成，
 * 1: 数据正确，传输未完成
 */
int httpRequest_prase(WebUser *user,char *recive_data,int length){
	chunk_length=-1;
	http_head_completed=0;
	current_User=user;
	char *data;
	int data_length=0;
	if(user->requestData){
		data_length=user->requestData->lefttoparselen+length;
		data=safe_alloc(data_length+1);
		data[0]='\0';
		if(user->requestData->lefttoparselen>0){
			strlcat(data,user->requestData->lefttoparse,data_length+1);
		}
		strlcat(data,recive_data,data_length+1);
		data[data_length]='\0';
		web_requestData_free(user->requestData);
	}
	else{
		data_length=length;
		data=safe_alloc(data_length+1);
		data[0]='\0';
		strlcat(data,recive_data,data_length+1);
		data[length]='\0';
	}
	//创建requstData
	user->requestData=new_RequestData();
	llhttp_reset(parser);
	enum llhttp_errno err =llhttp_execute(parser, data, data_length);
	if (err == HPE_OK) {
		/* Successfully parsed! */
		if(httpRequestReceivedDone()){//传输完成
			user->requestStatus=REQUESTSTATUS_REQUEST_PROCES;
			return 1;
		}
		else{//传输未完成
			user->requestData->lefttoparse=data;
			user->requestData->lefttoparselen=data_length;
			user->requestStatus=REQUESTSTATUS_REQUEST_UNFINISH;
			return 0;
		}
	}
	else {
		user->requestStatus=REQUESTSTATUS_REQUEST_SYNTAX_ERROR;
		return 1;
	}
	
}
